package cn.itcast.account.service.impl;

import cn.itcast.account.entity.AccountFreeze;
import cn.itcast.account.mapper.AccountFreezeMapper;
import cn.itcast.account.mapper.AccountMapper;
import cn.itcast.account.service.AccountTCCService;
import com.pr.constant.TipMessageConstant;
import com.pr.util.IdempotentUtil;
import io.seata.core.context.RootContext;
import io.seata.rm.tcc.api.BusinessActionContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.util.Objects;

@Service
@Slf4j
public class AccountTCCServiceImpl implements AccountTCCService {

    @Autowired
    private AccountMapper accountMapper;
    @Autowired
    private AccountFreezeMapper freezeMapper;

    @Override
    @Transactional
    public void deduct(String userId, int money) {
        String xid = RootContext.getXID();
        log.info("开启第一阶段try事务，事务id为：{}",xid);
        //事务进行第一阶段（try）之前，根据事务id查询事务记录（防止事务悬挂场景，不能被提交也不能被回滚）
        //todo 防止业务悬挂场景
        AccountFreeze accountFreeze = freezeMapper.selectAccountFreezeByXid(xid);
        if (!ObjectUtils.isEmpty(accountFreeze) && accountFreeze.getState().equals(AccountFreeze.State.CANCEL)){
            throw new RuntimeException(TipMessageConstant.TRANSACTION_ALREADY_BE_CANCEL);
        }
        //扣减可用余额
        accountMapper.deduct(userId, money);
        // 保存事务日志
        AccountFreeze freeze = new AccountFreeze();
        freeze.setUserId(userId);
        freeze.setFreezeMoney(money);
        freeze.setState(AccountFreeze.State.TRY);
        freeze.setXid(xid);
        freezeMapper.insert(freeze);
        //将事务标识xid放入map作为幂等性判断的依据
        //IdempotentUtil.add(getClass(),xid,System.currentTimeMillis());
    }

    @Override
    public boolean confirm(BusinessActionContext ctx) {
        //获取事务id
        String xid = ctx.getXid();
        //校验幂等性，防止重复提交
        //if (Objects.isNull(IdempotentUtil.get(getClass(), xid))){
        //    return true;
        //}
        //事务提交之前判断当前事务的状态是否是Try阶段
        log.info("开启第二阶段commit提交事务，事务id为：{}",xid);
        AccountFreeze accountFreeze = freezeMapper.selectById(xid);
        if (Objects.isNull(accountFreeze)){
            log.error("出现业务悬挂场景直接返回，业务悬挂场景在Try阶段校验");
            return true;
        }
        if (accountFreeze.getState().equals(AccountFreeze.State.CONFIRM)){
            log.error("出现重复提交场景直接返回实现幂等");
            return true;
        }
        //根据id删除冻结记录
        freezeMapper.deleteById(xid);
        //IdempotentUtil.remove(getClass(),xid);
        return true;
    }

    @Override
    public boolean cancel(BusinessActionContext ctx) {
        //获取事务id
        String xid = ctx.getXid();
        //校验幂等性，防止重复回滚
        //if (Objects.isNull(IdempotentUtil.get(getClass(), xid))){
        //    return true;
        //}
        log.info("开启第二阶段rollback回滚事务，事务id为：{}",xid);
        AccountFreeze accountFreeze = freezeMapper.selectById(xid);
        if (Objects.isNull(accountFreeze)){
            log.error("出现业务悬挂场景直接返回，业务悬挂场景在Try阶段校验");
            return true;
        }
        if (accountFreeze.getState().equals(AccountFreeze.State.CANCEL)){
            log.error("出现重复回滚场景直接返回实现幂等");
            return true;
        }
        //查询冻结记录
        AccountFreeze freeze = freezeMapper.selectById(xid);
        //恢复可用余额
        accountMapper.refund(freeze.getUserId(), freeze.getFreezeMoney());
        //将冻结金额清零，状态改为CANCEL
        freeze.setFreezeMoney(0);
        freeze.setState(AccountFreeze.State.CANCEL);
        freezeMapper.updateById(freeze);
        //IdempotentUtil.remove(getClass(),xid);
        return true;
    }
}
